#include "RtcInitHelper.h"
#include "I2cCommunicationModule.h"

#include <hc32_ll_utility.h>
#include <string.h>
#include <time.h>

//RTC Config
void App_RTCCfg(void) {
  // 如果RTC已经被初始化，就不再重新初始化了
  if (ENABLE == RTC_GetCounterState()) {
    return;
  }

  stc_rtc_init_t stcRtcInit;
  stc_rtc_date_t stcRtcDate;
  stc_rtc_time_t stcRtcTime;
  stc_rtc_alarm_t stcRtcAlarm;

  /* Reset RTC counter */
  if (LL_ERR_TIMEOUT != RTC_DeInit()) {
    /* Configure structure initialization */
    (void) RTC_StructInit(&stcRtcInit);

    /* Configuration RTC structure */
    stcRtcInit.u8ClockSrc = RTC_CLK_SRC_XTAL32;
    stcRtcInit.u8HourFormat = RTC_HOUR_FMT_24H;
    stcRtcInit.u8IntPeriod = RTC_INT_PERIOD_PER_HOUR;
    stcRtcInit.u8ClockCompen = RTC_CLK_COMPEN_ENABLE;
    stcRtcInit.u16CompenValue = (uint16_t) 0;
    stcRtcInit.u8CompenMode = RTC_CLK_COMPEN_MD_DISTRIBUTED;
    (void) RTC_Init(&stcRtcInit);

    /* Configuration alarm clock time */
    stcRtcAlarm.u8AlarmHour = 0x12U;
    stcRtcAlarm.u8AlarmMinute = 0x0U;
    stcRtcAlarm.u8AlarmWeekday = RTC_ALARM_WEEKDAY_SUNDAY | RTC_ALARM_WEEKDAY_MONDAY | RTC_ALARM_WEEKDAY_TUESDAY | RTC_ALARM_WEEKDAY_WEDNESDAY | RTC_ALARM_WEEKDAY_THURSDAY | RTC_ALARM_WEEKDAY_FRIDAY | RTC_ALARM_WEEKDAY_SATURDAY;
    stcRtcAlarm.u8AlarmAmPm = RTC_HOUR_24H;
    (void) RTC_SetAlarm(RTC_DATA_FMT_BCD, &stcRtcAlarm);
    RTC_AlarmCmd(ENABLE);

    /* Update date and time */
    /* Date configuration */
    stcRtcDate.u8Year = 1U;
    stcRtcDate.u8Month = RTC_MONTH_JANUARY;
    stcRtcDate.u8Day = 1U;
    stcRtcDate.u8Weekday = RTC_WEEKDAY_SUNDAY;

    /* Time configuration */
    stcRtcTime.u8Hour = 0U;
    stcRtcTime.u8Minute = 0U;
    stcRtcTime.u8Second = 0U;
    stcRtcTime.u8AmPm = RTC_HOUR_24H;

    if (LL_OK != RTC_SetDate(RTC_DATA_FMT_DEC, &stcRtcDate)) {
      return;
    }

    if (LL_OK != RTC_SetTime(RTC_DATA_FMT_DEC, &stcRtcTime)) {
      return;
    }

    /* Enable RTC interrupt */
    RTC_IntCmd(RTC_INT_PERIOD | RTC_INT_ALARM, ENABLE);
    /* Startup RTC count */
    RTC_Cmd(ENABLE);
  }

  // 初始化完成后直接先组合一次时间字符串，避免字符串为空
}

_ARMABI clock_t clock(void) {
  return SysTick_GetTick();
}

// 内部RTC周期中断
void INT_SRC_RTC_PRD_IrqCallback(void) {
  //ULOG_DEBUG("get a rtc pre hour invc start!\n");
  if (rtc_ctrl_task.time_update_squence_type == RTC_FLASH_PRE_HOUR) {
    rt_event_send(&(rtc_ctrl_task.rtc_ctrl_event), EVENT_EXT_RTC_START_CHECK_TIME_TASK);
  }
}

// 内部RTC闹钟中断。每天0点启动
void INT_SRC_RTC_ALM_IrqCallback(void) {
  //ULOG_DEBUG("get a rtc alert invc at 00:00:00 !\n");
  if (rtc_ctrl_task.time_update_squence_type == RTC_FLASH_PRE_DAY) {
    rt_event_send(&(rtc_ctrl_task.rtc_ctrl_event), EVENT_EXT_RTC_START_CHECK_TIME_TASK);
  }
}

/** \brief RTC中断
*
*/
/* INT_SRC_TMR2_1_CMP_A Callback. */

/*= 外部RTC中断 =*/

// 外部RTC输入中断1
void INT_SRC_PORT_EIRQ8_IrqCallback(void) {
  if (GPIO_ReadInputPins(RTC_INT_PORT, RTC_INT_PIN) == PIN_SET) {

    TMR2_Stop(CM_TMR2_1, TMR2_CH_A);
    TMR2_SetCountValue(CM_TMR2_1, TMR2_CH_A, 0U);
    TMR2_Start(CM_TMR2_1, TMR2_CH_A);
    sys_time_info.millisecond = 0;

    // 启动秒更新任务
    // 注意，因为在主函数循环中清除了事件状态。因此任何运行优先级低于主函数的线程都无法接收到秒中断！
    rt_event_send(&rtc_ctrl_task.rtc_ctrl_event, EVENT_EXT_RTC_GET_SEC_INTC);
  } else {
		rt_event_send(&rtc_ctrl_task.rtc_ctrl_event, EVENT_EXT_RTC_GET_HALF_SEC_INTC);
  }
}


// 构建iso时间字符串
char time_build_buf[8];
rt_err_t Build_Rtc_Time_Str_Interface(Time_Info_Def *obj) {
  size_t str_index = 0;
  size_t str_buf_size = 0;
  memset(time_build_buf, 0, 8);
  memset(obj->iso_time_str, 0, 32);
  obj->iso_time_str[str_index++] = '2';
  obj->iso_time_str[str_index++] = '0';
  // 填充年
  str_buf_size = itoa(obj->time_info.tm_year % 100, time_build_buf, 2);
  memcpy(obj->iso_time_str + str_index, time_build_buf, 2);
  str_index += str_buf_size;
  obj->iso_time_str[str_index++] = '-';
  // 月份
  str_buf_size = itoa(obj->time_info.tm_mon, time_build_buf, 2);
  memcpy(obj->iso_time_str + str_index, time_build_buf, 2);
  str_index += str_buf_size;
  obj->iso_time_str[str_index++] = '-';
  // 日
  str_buf_size = itoa(obj->time_info.tm_mday, time_build_buf, 2);
  memcpy(obj->iso_time_str + str_index, time_build_buf, 2);
  str_index += str_buf_size;
  obj->iso_time_str[str_index++] = 'T';
  // 小时
  str_buf_size = itoa(obj->time_info.tm_hour, time_build_buf, 2);
  memcpy(obj->iso_time_str + str_index, time_build_buf, 2);
  str_index += str_buf_size;
  obj->iso_time_str[str_index++] = ':';
  // 分钟
  str_buf_size = itoa(obj->time_info.tm_min, time_build_buf, 2);
  memcpy(obj->iso_time_str + str_index, time_build_buf, 2);
  str_index += str_buf_size;
  obj->iso_time_str[str_index++] = ':';
  // 秒
  str_buf_size = itoa(obj->time_info.tm_sec, time_build_buf, 2);
  memcpy(obj->iso_time_str + str_index, time_build_buf, 2);
  str_index += str_buf_size;
  obj->iso_time_str[str_index++] = '.';
  // 毫秒
  str_buf_size = itoa(obj->millisecond, time_build_buf, 3);
  memcpy(obj->iso_time_str + str_index, time_build_buf, 3);
  str_index += 3;
  obj->iso_time_str[str_index++] = '+';
  obj->iso_time_str[str_index++] = '0';
  obj->iso_time_str[str_index++] = '8';
  obj->iso_time_str[str_index++] = '0';
  obj->iso_time_str[str_index++] = '0';

  return RT_EOK;
}// 构建iso时间字符串

// 从内部RTC读取时间信息
rt_err_t Update_Time_From_Innner_Rtc_Delay_Interface(Time_Info_Def *obj) {
  // 锁定资源。
  if (strlen(obj->rtc_lock.parent.parent.name) != 0) {// 只有初始化了保护锁才会检查
    uint8_t get_mutex = 0;
    while (rt_mutex_take(&(obj->rtc_lock), 50 * (2 ^ get_mutex)) != RT_EOK) {
      if (get_mutex >= 3) {
        return RT_EBUSY;
      }
      get_mutex++;
    }
  }

  stc_rtc_date_t pstcRtcDate;
  RTC_GetDate(RTC_DATA_FMT_DEC, &pstcRtcDate);
  stc_rtc_time_t pstcRtcTime;
  RTC_GetTime(RTC_DATA_FMT_DEC, &pstcRtcTime);

  obj->time_info.tm_year = 2000 + pstcRtcDate.u8Year;
  obj->time_info.tm_mon = pstcRtcDate.u8Month;
  obj->time_info.tm_mday = pstcRtcDate.u8Day;
  obj->time_info.tm_hour = pstcRtcTime.u8Hour;
  obj->time_info.tm_min = pstcRtcTime.u8Minute;
  obj->time_info.tm_sec = pstcRtcTime.u8Second;

  if (strlen(obj->rtc_lock.parent.parent.name) != 0) {// 只有初始化了保护锁才会检查
    rt_mutex_release(&(obj->rtc_lock));
  }

  return RT_EOK;
}// 从内部RTC读取时间信息

// 将时间写入内部RTC
rt_err_t Update_Time_To_Innner_Rtc_Delay_Interface(Time_Info_Def *obj) {
  // 锁定资源。
  if (strlen(obj->rtc_lock.parent.parent.name) != 0) {// 只有初始化了保护锁才会检查
    uint8_t get_mutex = 0;
    while (rt_mutex_take(&(obj->rtc_lock), 50 * (2 ^ get_mutex)) != RT_EOK) {
      if (get_mutex >= 3) {
        return RT_EBUSY;
      }
      get_mutex++;
    }
  }

  // 注意函数没法解决同步问题

  stc_rtc_date_t pstcRtcDate;
  stc_rtc_time_t pstcRtcTime;

  pstcRtcDate.u8Year = DEC2BCD((obj->time_info.tm_year) % 100);
  pstcRtcDate.u8Month = DEC2BCD(obj->time_info.tm_mon);
  pstcRtcDate.u8Weekday = obj->tmp_time_info.week_bcd;
  pstcRtcDate.u8Day = DEC2BCD(obj->tmp_time_info.day_bcd);
  pstcRtcTime.u8AmPm = 0x01;// 这里恒定是1，代表24小时制，如果是0就是12小时制
  pstcRtcTime.u8Hour = DEC2BCD(obj->time_info.tm_hour);
  pstcRtcTime.u8Minute = DEC2BCD(obj->time_info.tm_min);
  pstcRtcTime.u8Second = DEC2BCD(obj->time_info.tm_sec);

  RTC_SetDate(RTC_DATA_FMT_BCD, &pstcRtcDate);
  RTC_SetTime(RTC_DATA_FMT_BCD, &pstcRtcTime);

  obj->tmp_time_info.update_finished = false;

  if (strlen(obj->rtc_lock.parent.parent.name) != 0) {// 只有初始化了保护锁才会检查
    rt_mutex_release(&(obj->rtc_lock));
  }
  return RT_EOK;
}// 将时间写入内部RTC

// 将临时缓冲区的数据刷新进入时间结构体
rt_err_t Flash_Tmp_To_Time_Interface(Time_Info_Def *obj) {
  obj->time_info.tm_year = 2000 + BCD2DEC(obj->tmp_time_info.year_bcd);
  obj->time_info.tm_mon = BCD2DEC(obj->tmp_time_info.mon_bcd);
  obj->time_info.tm_mday = BCD2DEC(obj->tmp_time_info.day_bcd);
  obj->time_info.tm_hour = BCD2DEC(obj->tmp_time_info.hour_bcd);
  obj->time_info.tm_min = BCD2DEC(obj->tmp_time_info.min_bcd);
  obj->time_info.tm_sec = BCD2DEC(obj->tmp_time_info.sec_bcd);
  return RT_EOK;
}// 将临时缓冲区的数据刷新进入时间结构体

// 获取时间字符串
rt_err_t Get_Time_Str_Safe_Interface(Time_Info_Def *obj, char *str_buf) {
  if (RT_NULL == str_buf) {
    return RT_EEMPTY;
  }

  if (strlen(obj->iso_time_str) <= 0) {
    obj->Ext_Rtc_Flash_Inner_Rtc_And_Tm_Time_Info(obj);
    obj->Build_Rtc_Time_Str(obj);
  }

  // 防止被中断打断
  rt_interrupt_enter();
  strcpy(str_buf, obj->iso_time_str);
  rt_interrupt_leave();

  return RT_EOK;
}// 获取时间字符串

// 获取时间字符串时刷新毫秒
char msec_str_buf_size[8];
char *Get_Milsecond_Iso_Str_Initerface(Time_Info_Def *obj) {
  // 锁定资源。
  if (strlen(obj->rtc_lock.parent.parent.name) != 0) {// 只有初始化了保护锁才会检查
    uint8_t get_mutex = 0;
    while (rt_mutex_take(&(obj->rtc_lock), 50 * (2 ^ get_mutex)) != RT_EOK) {
      if (get_mutex >= 3) {
        return obj->iso_time_str;// 这里无论如何都要返回一个字符串回去
      }
      get_mutex++;
    }
  }
  itoa(obj->millisecond, msec_str_buf_size, 3);
  memcpy(obj->iso_time_str + 20, msec_str_buf_size, 3);

  if (strlen(obj->rtc_lock.parent.parent.name) != 0) {// 只有初始化了保护锁才会检查
    rt_mutex_release(&(obj->rtc_lock));
  }
  return obj->iso_time_str;
}// 获取时间字符串时刷新毫秒

// 无延迟的将外部RTC刷入内部RTC刷新时间
rt_err_t Ext_Rtc_Flash_Inner_Rtc_And_Tm_Time_Info_Interface(struct __Tag_Time_Info_Def *obj) {
  rt_err_t res = RT_EOK;
  // rtc进入读写状态
  // EnterRwMode
  if (0UL != READ_REG32(bCM_RTC->CR1_b.START)) {
    if (1UL != READ_REG32(bCM_RTC->CR2_b.RWEN)) {
      __IO uint32_t u32Count;
      WRITE_REG32(bCM_RTC->CR2_b.RWREQ, SET);
      u32Count = 100 * (HCLK_VALUE / 20000UL);
      while (1UL != READ_REG32(bCM_RTC->CR2_b.RWEN)) {
        if (0UL == u32Count) {
          res = RT_EIO;
          break;
        }
        u32Count--;
        rt_thread_yield();
      }
    }
  }// EnterRwMode
  if (res == RT_EOK) {
    // 开始刷新外部RTC进入内部时间管理
    if (Sd8804_Read_Data_Time(&rtc_ctrl_task, &sys_time_info) != RT_EOK) {
      res = RT_ERROR;
    } else {// 刷新完成开始写入。前面不用锁定，因为读取外部RTC也会锁定RTC
      // 锁定资源。
      if (strlen(obj->rtc_lock.parent.parent.name) != 0) {// 只有初始化了保护锁才会检查
        uint8_t get_mutex = 0;
        while (rt_mutex_take(&(obj->rtc_lock), 50 * (2 ^ get_mutex)) != RT_EOK) {
          if (get_mutex >= 3) {
            return RT_EBUSY;
          }
          get_mutex++;
        }
      }
      // 开始写入时间
      WRITE_REG8(CM_RTC->YEAR, DEC2BCD(sys_time_info.time_info.tm_yday % 100));
      WRITE_REG8(CM_RTC->MON, DEC2BCD(sys_time_info.time_info.tm_mon));
      WRITE_REG8(CM_RTC->DAY, DEC2BCD(sys_time_info.time_info.tm_mday));
      WRITE_REG8(CM_RTC->WEEK, 0x00);// 默认周日，因为没啥用所以不算了
      // 这里不用算APAM，因为那个用来计算12小时制的。这里12小时制寄存器是要在初始化修改的，这里没法修改。
      WRITE_REG8(CM_RTC->HOUR, DEC2BCD(sys_time_info.time_info.tm_hour));
      WRITE_REG8(CM_RTC->MIN, DEC2BCD(sys_time_info.time_info.tm_min));
      WRITE_REG8(CM_RTC->SEC, DEC2BCD(sys_time_info.time_info.tm_sec));
    }
    /* Exit read/write mode */
    // ExitRwMode
    if (0UL != READ_REG32(bCM_RTC->CR1_b.START)) {
      if (0UL != READ_REG32(bCM_RTC->CR2_b.RWEN)) {
        __IO uint32_t u32Count;
        WRITE_REG32(bCM_RTC->CR2_b.RWREQ, RESET);
        u32Count = 100 * (HCLK_VALUE / 20000UL);
        while (0UL != READ_REG32(bCM_RTC->CR2_b.RWEN)) {
          if (0UL == u32Count) {
            res = RT_EIO;
            break;
          }
          u32Count--;
          rt_thread_yield();
        }
      }
    }// ExitRwMode
  }

  if (strlen(obj->rtc_lock.parent.parent.name) != 0) {// 只有初始化了保护锁才会检查
    rt_mutex_release(&(obj->rtc_lock));
  }

  return res;
}

// 初始化时间结构体
rt_err_t Init_Time_Info_Obj(Time_Info_Def *obj, char *name) {
  if (RT_NULL == name) {
    return RT_EEMPTY;
  }
  char str_buf[16] = {0};
  rt_sprintf(str_buf, "%s_lock", name);
  rt_mutex_init(&(obj->rtc_lock), str_buf, RT_IPC_FLAG_PRIO);

  memset(obj->iso_time_str, 0, 32);
  obj->millisecond = 0;
  obj->time_info.tm_year = 2000;
  obj->time_info.tm_mon = 12;
  obj->time_info.tm_mday = 1;
  obj->time_info.tm_hour = 0;
  obj->time_info.tm_min = 0;
  obj->time_info.tm_sec = 0;
  obj->week_update = false;
  strcpy(obj->name, name);

  // 设置临时时间
  obj->tmp_time_info.update_finished = false;
  obj->tmp_time_info.year_bcd = 0;
  obj->tmp_time_info.mon_bcd = 1;
  obj->tmp_time_info.day_bcd = 1;
  obj->tmp_time_info.week_bcd = 0x01;
  obj->tmp_time_info.hour_bcd = 0;
  obj->tmp_time_info.min_bcd = 0;
  obj->tmp_time_info.sec_bcd = 0;

  obj->Build_Rtc_Time_Str = Build_Rtc_Time_Str_Interface;
  obj->Get_Time_Str_Safe = Get_Time_Str_Safe_Interface;
  obj->Update_Time_From_Innner_Rtc_Delay = Update_Time_From_Innner_Rtc_Delay_Interface;
  obj->Update_Time_To_Innner_Rtc_Delay = Update_Time_To_Innner_Rtc_Delay_Interface;
  obj->Flash_Tmp_To_Time = Flash_Tmp_To_Time_Interface;
  obj->Get_Milsecond_Iso_Str = Get_Milsecond_Iso_Str_Initerface;
  obj->Ext_Rtc_Flash_Inner_Rtc_And_Tm_Time_Info = Ext_Rtc_Flash_Inner_Rtc_And_Tm_Time_Info_Interface;

  return RT_EOK;
}
// 初始化时间结构体
